import os
import time

import uiautomator2 as u2
from loguru import logger
from uiautomator2 import Direction
from xml.etree.ElementTree import fromstring, ElementTree

from common import utils


class UiAutomator2:
    def __init__(self, ip, port=5555):
        self.ip = ip
        self.port = port
        self.d = self.u2_connect()

    def u2_connect(self):
        return u2.connect('{}:{}'.format(self.ip, self.port))

    def click_point(self, x, y):
        if isinstance(x, str):
            x = float(x)
        if isinstance(y, str):
            y = float(y)
        self.d.click(x, y)

    def click_text(self, text):
        self.d(text=text).click()

    def click_description(self, description):
        self.d(description=description).click()

    def click_resource_id(self, resource_id):
        self.d(resourceId=resource_id).click()

    def click_text_con(self, text):
        # 这个重写的目的在于点击后延迟0.5秒
        self.d(textContains=text).click()
        time.sleep(0.5)

    def press(self, key, meta=None):
        # home, back, left, right, up, down, center, menu, search, enter
        self.d.press(key, meta)

    def get_all_text(self):
        time.sleep(1)
        all_text = []
        for el in self.d.xpath('//android.view.View').all():
            if el.text:
                all_text.append(el.text)
        logger.debug('Get the page text as={}'.format(all_text))
        return all_text

    def click_edit_text(self):
        all_point = []
        for el in self.d.xpath('//android.widget.EditText').all():
            coord = el.bounds
            all_point.append(utils.get_bounds_center(coord))
        if not all_point:
            raise Exception('not find EditText in this view')
        self.click_point(all_point[-1][0], all_point[-1][1])
        return all_point[-1]

    def wait_element(self, text):
        self.d.xpath(text).wait(timeout=5)
        # self.d.watcher.when(text)

    def screenshot(self, name):
        base_dir = os.path.dirname(__file__)
        screenshot_dir = os.path.join(base_dir, '../../data/screenshot')
        utils.make_dirs_if_not_exist(screenshot_dir)
        file_name = time.strftime("%Y-%m-%d %H-%M-%S", time.localtime())
        if name:
            file_name = "{} {}.jpg".format(file_name, name)

        file_path = os.path.abspath(os.path.join(screenshot_dir, file_name))
        cmd = 'uiautomator2 -s {} screenshot "{}"'.format(self.ip, file_path)
        utils.get_execute_cmd_result(cmd)

    def set_input_text(self, text):
        self.click_edit_text()
        self.d.set_fastinput_ime(True)
        self.d.send_keys(text, clear=True)
        time.sleep(0.5)
        # self.d.send_action("enter")

    def press_button(self, button):
        self.d.press(button)

    def get_clipboard(self):
        return self.d.clipboard

    def start_app(self, package_name):
        self.d.app_start(package_name)

    def start_activity(self, package_name, activity_name):
        self.d.app_start(package_name, activity_name)

    def click_xpath(self, xpath_string):
        self.d.xpath(xpath_string).click()

    def click_xpath_if_exist(self, xpath_string):
        a = self.d.xpath(xpath_string).all()
        if a:
            self.click_xpath(xpath_string)
            time.sleep(0.5)
        else:
            self.d.press("home")
            time.sleep(0.5)
            self.d.press("back")

    def ui_auto2_unlock_screen(self):
        self.d.unlock()

    def check_screen_is_on(self):
        return self.d.info['screenOn']

    def get_text_count(self, text):
        return self.d(text=text).count

    # @retry(wait_fixed=6000, stop_max_attempt_number=10)
    # def __check_phone_connected(self):
    #     try:
    #         logger.debug('try to connect {}'.format(self.ip))
    #         self.adb.adb_connect()
    #     except Exception as e:
    #         err_msg = 'connect {} failed, err={}'.format(self.ip, e)
    #         logger.error(err_msg)
    #         raise Exception(err_msg)
    #
    # def check_phone_connected(self):
    #     self.__check_phone_connected()

    def cancel_update(self):
        flag = self.d(text="立即下载").exists(timeout=3)
        if flag:
            self.d(text='取消').click()
            logger.warning('have update, cancel it!')

    def swipe(self, fx, bl):
        # 对页面进行滑动，判断出现对应的选项才停止，还有翻页的功能，补充
        # 翻页屏幕的比例
        self.d.swipe_ext(fx, scale=bl)

    def swipe_dire(self):
        # 翻页屏幕的比例 #Direction.FORWARD；Direction.BACKWARD；Direction.HORIZ_FORWARD；
        self.d.swipe_ext(Direction.FORWARD)

    def swipe_x(self, x, y, distance):
        # 向左是负，向右是正
        height, width = self.get_height_width()
        if distance < 1:
            distance = width * distance
        tx = max(x + distance, 0)
        tx = min(tx, width)
        self.d.swipe(x, y, tx, y)

    def swipe_y(self, x, y, distance):
        # 向上是负，向下是正
        height, width = self.get_height_width()
        if distance < 1:
            distance = height * distance
        ty = max(y + distance, 0)
        ty = min(ty, height)
        self.d.swipe(x, y, x, ty)

    def get_height_width(self):
        height = self.d.info['displayHeight']
        width = self.d.info['displayWidth']
        return height, width

    def xpath_set(self, xpath_string, content):
        self.d.xpath(xpath_string).set_text(content)

    def wid_all(self):
        # 针对地址，获取对应的全部文本
        alltext = []
        for el in self.d.xpath('//android.widget.TextView').all():
            alltext.append(el)
        return alltext

    # def dt(self, text):
    #     self.d(text=text)
    #     return self.d(text=text)

    def click_xp_ct(self, xpath_string):
        # 只用来对滴付款的text进行点击

        # self.d.xpath(xpath_string).position(0.5,0.5).click()
        # 通过XPathSelector.get() 返回的对象叫做 XMLElement
        el = self.d.xpath(xpath_string).get()
        lx, ly, width, height = el.rect  # 获取左上角坐标和宽高
        lx, ly, rx, ry = el.bounds  # 左上角与右下角的坐标
        x, y = el.center()  # get element center position
        # x, y = el.offset(0.5, 0.5)  # same as center()
        # send click
        el.click()
        # 打印文本内容
        # print(el.text)
        # 获取组内的属性, dict类型
        # print(el.attrib)

    def get_xpath_center(self, xpath_string):
        el = self.d.xpath(xpath_string).get()
        x, y = el.center()  # get element center position
        return x, y

    def gettext(self, xpath_string):
        # alltext = []
        el = self.d.xpath(xpath_string).get()
        print(el.text)
        return el.text

    def beexist(self, xpath_string):
        sl = self.d.xpath(xpath_string)
        el = sl.wait()
        # if not sl.exists:
        #     self.d.xpath.implicitly_wait(5)  # 与上一行代码等价
        print(sl.exists)
        return sl.exists

    def exist(self, xpath_string):
        # 判断存在以后，会一直显示True，即使这个元素已经消失了，
        sl = self.d.xpath(xpath_string)
        # print(sl.exists)
        return sl.exists

    def check_text_is_exist(self, text, timeout=10):
        return self.d(text=text).exists(timeout=timeout)

    def check_description_is_exist(self, description, timeout=10):
        return self.d(description=description).exists(timeout=timeout)

    def health_check(self):
        return self.d.healthcheck()

    def dump_hierarchy(self):
        return self.d.dump_hierarchy()

    def get_page_attrib(self, only_text=True, only_package=None):
        root = ElementTree(fromstring(self.d.dump_hierarchy()))
        value_list = []
        for i in root.iter():
            value = i.attrib
            if only_text:
                if not value.get('text') and not value.get('content-desc'):
                    continue
                else:
                    if value.get('text', '') == value.get('content-desc', ''):
                        value['only_text'] = value.get('text', '')
                    elif value.get('text', ''):
                        value['only_text'] = value.get('text', '')
                    else:
                        value['only_text'] = value.get('content-desc', '')
            if only_package:
                if value.get('package') not in only_package:
                    continue
            value_list.append(value)
        return value_list
